package inglar.autotc.client.ui;

import inglar.autotc.shared.Values;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.DialogBox;
import com.google.gwt.user.client.ui.DoubleBox;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.HasAlignment;
import com.google.gwt.user.client.ui.HasVerticalAlignment;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.IntegerBox;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;

public class DialogBoxEditNodeClass extends DialogBox {
	
	VerticalPanel contentPanel;
	
	public TextBox txtbxParent;
	public TextBox txtbxClassid;
	private HorizontalPanel panelOptions;
	public ListBox listClass;
	public Label lblQdiscName;

	private VerticalPanel panelHtb;
	public IntegerBox intbxHtbPrio;
	public DoubleBox dblbxHtbRate; // required, minimum is 1bps
	public DoubleBox dblbxHtbCeil; // required, minimum is 1bps
	public DoubleBox dblbxHtbBurst;
	public DoubleBox dblbxHtbCburst; // required, minimum is 1bps
	
	NodeClass targetClass;

	public DialogBoxEditNodeClass() {
		setHTML("Class Editor");
		setGlassEnabled(false);
		setModal(true);
		
		contentPanel = new VerticalPanel();
		contentPanel.setHorizontalAlignment(HasAlignment.ALIGN_CENTER);
		setWidget(contentPanel);
		contentPanel.setSize("100%", "100%");
		
		FlexTable tblNodeDesc = new FlexTable();
		contentPanel.add(tblNodeDesc);
		
		Label lblParent = new Label("Parent:");
		tblNodeDesc.setWidget(0, 0, lblParent);
		
		txtbxParent = new TextBox();
		txtbxParent.setText("Parent");
		tblNodeDesc.setWidget(0, 1, txtbxParent);
		
		Label lblHandle = new Label("Handle:");
		tblNodeDesc.setWidget(0, 2, lblHandle);
//		lblHandle.setTitle("");
		
		txtbxClassid = new TextBox();
		txtbxClassid.setText("Flow ID");
		tblNodeDesc.setWidget(0, 3, txtbxClassid);
		
		Label lblQdisc = new Label("QDisc:");
		tblNodeDesc.setWidget(1, 0, lblQdisc);
		
		HorizontalPanel panel1 = new HorizontalPanel();
		tblNodeDesc.setWidget(1, 1, panel1);
		tblNodeDesc.getFlexCellFormatter().setColSpan(1, 1, 3);
		panel1.setVerticalAlignment(HasVerticalAlignment.ALIGN_MIDDLE);
		
		listClass = new ListBox();
		panel1.add(listClass);
		for(int i = 0; i < NodeClass.classes.length; i++) {
			if(NodeClass.classes[i].equals("prio")) continue;
			listClass.addItem(NodeClass.classes[i]);
		}
		listClass.setSelectedIndex(0);
		listClass.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				String q = listClass.getItemText(listClass.getSelectedIndex());
				setClass(q);
			}
		});
		
		lblQdiscName = new Label("");
		panel1.add(lblQdiscName);
		lblQdiscName.getElement().setAttribute("style", "margin-left: 10px;");
		
		panelOptions = new HorizontalPanel();
		contentPanel.add(panelOptions);
		panelOptions.getElement().setAttribute("style", "margin-top: 5px; margin-bottom: 5px;");
		
		HorizontalPanel panel2 = new HorizontalPanel();
		contentPanel.add(panel2);
		
		Button btnApply = new Button("Apply");
		panel2.add(btnApply);
		btnApply.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				if(apply()) {
					targetClass.tsRef.setTreeSaved(false);
					hide();
				}
			}
		});
		btnApply.getElement().setAttribute("style", "margin-left: 5px; margin-right: 5px;");
		
		Button btnCancel = new Button("Cancel");
		panel2.add(btnCancel);
		btnCancel.addClickHandler(new ClickHandler() {
			@Override
			public void onClick(ClickEvent event) {
				hide(); // end the popup
			}
		});
		btnCancel.getElement().setAttribute("style", "margin-left: 5px; margin-right: 5px;");
		
		// htb opts
		panelHtb = new VerticalPanel();
		FlexTable table1 = new FlexTable();
		panelHtb.add(table1);
		Label lblHtbRate = new Label("rate:");
		table1.setWidget(0, 0, lblHtbRate);
		lblHtbRate.setTitle("Maximum rate this class and all its children are guaranteed. This field is required.");
		dblbxHtbRate = new DoubleBox();
		table1.setWidget(0, 1, dblbxHtbRate);
		table1.setWidget(0, 2, new Label("bytes per second"));
		Label lblHtbPrio = new Label("prio:");
		table1.setWidget(1, 0, lblHtbPrio);
		lblHtbPrio.setTitle("Classes with the lowest priority field are tried for packets first.");
		intbxHtbPrio = new IntegerBox();
		table1.setWidget(1, 1, intbxHtbPrio);
		Label lblHtbBurst = new Label("burst:");
		table1.setWidget(2, 0, lblHtbBurst);
		lblHtbBurst.setTitle("Amount of bytes that can be burst at ceil speed, in excess of the configured rate. Should be at least as high as the highest burst of all children.");
		dblbxHtbBurst = new DoubleBox();
		table1.setWidget(2, 1, dblbxHtbBurst);
		table1.setWidget(2, 2, new Label("bytes"));
		Label lblHtbCeil = new Label("ceil:");
		table1.setWidget(3, 0, lblHtbCeil);
		lblHtbCeil.setTitle("Maximum rate at which a class can send, if its parent has bandwidth to spare. Defaults to the configured rate, which implies no borrowing.");
		dblbxHtbCeil = new DoubleBox();
		table1.setWidget(3, 1, dblbxHtbCeil);
		table1.setWidget(3, 2, new Label("bytes per second"));
		
		Label lblHtbCburst = new Label("cburst:");
		table1.setWidget(4, 0, lblHtbCburst);
		lblHtbCburst.setTitle("Amount of bytes that can be burst at 'infinite' speed, in other words, as fast as the interface can transmit them. For perfect evening out, should be equal to at most one average packet. Should be at least as high as the highest cburst of all children.");
		dblbxHtbCburst = new DoubleBox();
		table1.setWidget(4, 1, dblbxHtbCburst);
		table1.setWidget(4, 2, new Label("bytes"));
		
		setClass(listClass.getItemText(listClass.getSelectedIndex()));
	}

	public void setClass(String c) {
		panelOptions.clear();
		if(c.equals("htb")) {
			panelOptions.add(panelHtb);
			lblQdiscName.setText("Hierarchy Token Bucket");
		}
	}
	
	public void setTargetNode(NodeClass node) {
		txtbxParent.setText(node.getParentId());
		txtbxClassid.setText(node.getClassid());
		String c = node.getClassname();
		int listItems = listClass.getItemCount();
		for(int i = 0; i < listItems; i++) {
			if(listClass.getItemText(i).equals(c)) {
				listClass.setSelectedIndex(i);
				break;
			}
		}
		
		setClass(c);
		
		String opts = node.getOptions().trim();
		if(c.equals("htb")) {
			String[] u = opts.trim().split(Values.REGEX_ALL_WHITESPACE);
			int idxRate = -1, idxBurst = -1, idxPrio = -1, idxCeil = -1, idxCburst = -1;
			for(int i = 0; i < u.length; i++) {
				if(u[i].equals("rate")) idxRate = i;
				if(u[i].equals("burst")) idxBurst = i;
				if(u[i].equals("prio")) idxPrio = i;
				if(u[i].equals("ceil")) idxCeil = i;
				if(u[i].equals("cburst")) idxCburst = i;
			}
			if(idxRate != -1) {
				String rate = u[idxRate + 1];
				Double d = DialogBoxEditNodeQDisc.getBaseDouble(rate);
				dblbxHtbRate.setValue(d);
			}
			if(idxBurst != -1) {
				String burst = u[idxBurst + 1];
				Double d = DialogBoxEditNodeQDisc.getBaseDouble(burst);
				dblbxHtbBurst.setValue(d);
			}
			if(idxPrio != -1) {
				String prio = u[idxPrio + 1];
				Double d = DialogBoxEditNodeQDisc.getBaseDouble(prio);
				if(d != null) {
					Integer i = d.intValue();
					intbxHtbPrio.setValue(i);
				}
			}
			if(idxCeil != -1) {
				String ceil = u[idxCeil + 1];
				Double d = DialogBoxEditNodeQDisc.getBaseDouble(ceil);
				dblbxHtbBurst.setValue(d);
			}
			if(idxCburst != -1) {
				String cburst = u[idxCburst + 1];
				Double d = DialogBoxEditNodeQDisc.getBaseDouble(cburst);
				dblbxHtbCburst.setValue(d);
			}
		} 
		targetClass = node;
	}

	public boolean apply() {
		String opts = "";
		String c = listClass.getItemText(listClass.getSelectedIndex());
		String classid = txtbxClassid.getValue();
		targetClass.setClassid(classid);
		if(c.equals("htb")) {
			Double rate = dblbxHtbRate.getValue();
			if(rate == null) {
				Window.alert("Parameter 'rate' must have a valid value.");
				return false;
			} else {
				opts += "rate " + rate.doubleValue() + " ";
			}
			Double burst = dblbxHtbBurst.getValue();
			if(burst != null) {
				opts += "burst " + burst.doubleValue() + " ";
			}
			Integer prio = intbxHtbPrio.getValue();
			if(prio != null) {
				opts += "prio " + prio.intValue() + " ";
			}
			Double ceil = dblbxHtbCeil.getValue();
			if(ceil != null) {
				opts += "ceil " + ceil.doubleValue() + " ";
			}
			Double cburst = dblbxHtbCburst.getValue();
			if(cburst != null) {
				opts += "cburst " + cburst.doubleValue() + " ";
			}
			targetClass.setClassname(c);
			targetClass.setOptions(opts);
		}
		return true;
	}

}
